package lambda;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * @author jiangwz
 * @create 2019/8/27.
 */
public class LambdaTests {

    List<Dog> lists = new ArrayList<>();
    List<Dog> repeats = new ArrayList<>();
    List<Integer> nums = new ArrayList<>();

    @Before
    public void before() {
        for (int i = 0; i < 10; i++) {
            lists.add(new Dog("dog" + i, "likeMaster" + i));
            repeats.add(new Dog("dog", "likeMaster" + i));
            nums.add(i);
        }
        nums.add(1);

    }


    @Test
    public void testCollect() {
        List<String> strs = Arrays.asList("1", "2", "3");
        String string = strs.stream().collect(
                //第一个参数,用StringBuilder
                () -> new StringBuilder(),
                //第二个三叔,如何添加到容器
                (sb, x) -> sb.append(x),
                //第三个参数,容器如何合并
                (r1, r2) -> r1.append(r2)).toString();
        System.out.println(string);

        HashMap<String, String> collect = lists.stream().collect(
                //创建可变结果容器
                () -> new HashMap<String, String>(),
                (h, x) -> {
                    //加入容器操作
                    h.put(x.getName(), x.getLike());
                },
                //容器合并操作
                HashMap::putAll);
        System.out.println(collect);
    }

    @Test
    public void test06() {

        List<OrderDTO> orderDTOS = Lists.newArrayList(
                OrderDTO.builder().orderId(1L).strList(Arrays.asList("22")).build(),
                OrderDTO.builder().orderId(2L).strList(Arrays.asList("22")).build(),
                OrderDTO.builder().orderId(1L).strList(Arrays.asList("33")).build()
        );

        List<OrderDTO> list = orderDTOS.stream().collect(
                () -> Lists.newArrayList(),
                (l, o) -> {
                    boolean exits = false;
                    for (OrderDTO orderDTO : l) {
                        if (Objects.equals(orderDTO.getOrderId(), o.getOrderId())) {
                            exits = true;
                            ArrayList<String> strings = Lists.newArrayList(orderDTO.getStrList());
                            strings.addAll(o.getStrList());
                            orderDTO.setStrList(strings);
                        }
                    }
                    if (!exits) {
                        l.add(o);
                    }
                },
                List::addAll);

        System.out.println(list);
    }

    @Test
    public void test05() {
        System.out.println(nums.removeIf(i -> Objects.equals(i, 5)));
        System.out.println(nums);
    }

    @Test
    public void testReduce() {
        List<Integer> list = new ArrayList<>();
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);

        Optional<Integer> reduce = list.stream().reduce((var1, var2) -> var1 + var2);
        if (reduce.isPresent()) {
            System.out.println(reduce.get());
        }
        Integer num = list.stream().reduce(0, (a, b) -> a + b);
        System.out.println(num);
    }

    @Test
    public void testOrderSortByCondition() {
        List<Order> orders = Lists.newArrayList();
        orders.add(new Order(1, 10001, 2, DateUtil.parseDateTime("2021-06-08 18:00:00"), "A_10001"));
        orders.add(new Order(2, 10001, 1, DateUtil.parseDateTime("2021-06-07 18:00:00"), "A_10001"));
        orders.add(new Order(2, 10001, 1, DateUtil.parseDateTime("2021-06-07 18:00:01"), "A_10002"));
        orders.add(new Order(3, 10003, 1, DateUtil.parseDateTime("2021-06-08 18:00:01"), "D_10003"));
        orders.add(new Order(4, 999, 2, DateUtil.parseDateTime("2021-06-08 18:00:06"), "B_999"));
        orders.add(new Order(5, 998, 1, DateUtil.parseDateTime("2021-06-08 18:00:09"), "B_998"));
        orders.add(new Order(6, 998, 1, DateUtil.parseDateTime("2021-06-08 18:00:10"), "B_998"));
        orders.add(new Order(7, 998, 1, DateUtil.parseDateTime("2021-06-08 18:00:08"), "B_998"));

        Map<Integer, Integer> map = Maps.newHashMap();
        orders.forEach(order -> {
            map.putIfAbsent(order.getId(), order.getOrderStatus());
            if (order.getOrderStatus() != 10001 && order.getOrderStatus() != 10003) {
                order.setOrderStatus(10002);
            }
        });

        orders.stream()
                .filter(order -> order.getOrderType() != 2)
                .sorted(Comparator.comparing(Order::getCreateDate).reversed())
                .sorted(Comparator.comparing(Order::getOrderStatus))
                .peek(order -> order.setOrderStatus(map.get(order.getId())))
                .forEach(System.out::println);

    }

    @Test
    public void testSort() {

        Date date = DateUtil.parseDateTime("2021-06-08 18:00:00");
        Date date2 = DateUtil.parseDateTime("2021-06-08 18:00:01");
        List<Dog> dogs = Lists.newArrayList(
                new Dog("d1", "eat", date2),
                new Dog("d2", "eat2", date)
        );
        Dog dog = dogs.stream().sorted(Comparator.comparing(Dog::getBirthDate).reversed()).findFirst().orElse(null);
        System.out.println(dog);
    }

    @Test
    public void testFlatMap() {
        // 自增生成组编号
        AtomicInteger group = new AtomicInteger(1);
        // 自增生成学生编号
        AtomicInteger student = new AtomicInteger(1);
        List<String[]> eggs = new ArrayList<>();
        // 第一箱鸡蛋
        eggs.add(new String[]{"鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1"});
        // 第二箱鸡蛋
        eggs.add(new String[]{"鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2"});

        eggs.stream()
                .map(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎")))
                .forEach(x -> System.out.println("组" + group.getAndIncrement() + ":" + Arrays.toString(x.toArray())));

        // 有一个合并操作
        eggs.stream()
                .flatMap(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎")))
                .forEach(x -> System.out.println("学生" + student.getAndIncrement() + ":" + x));
    }

    @Test
    public void test04() {
        System.out.println(nums.stream().mapToInt(t -> t).sum());

        System.out.println(nums.stream().max(Comparator.comparingInt(t -> t)).get());
        System.out.println(nums.stream().min(Comparator.comparingInt(t -> t)).get());
        System.out.println(nums.stream().min((t, t1) -> t - t1).get());
        System.out.println();
        // 把数据进行整合计算
        System.out.println(nums.stream().reduce((acc, item) -> {
            System.out.print("acc : " + acc); //累计值
            System.out.println(" item: " + item);//当前遍历的值
            System.out.println("--------");
            return acc + item;
        }).get());

        // 一般用于合并操作，次操作无意义
        lists.stream().flatMap(u -> Stream.of(u)).collect(Collectors.toList()).forEach(System.out::println);

        System.out.println();
        Stream.of(lists, repeats).flatMap(u -> u.stream()).collect(Collectors.toList()).forEach(System.out::println);
        Stream.of(lists, repeats).flatMap(Collection::stream).collect(Collectors.toList()).forEach(System.out::println);
        Stream.of(lists, repeats).flatMap(u -> u.stream()).collect(Collectors.toList()).forEach(System.out::println);

    }

    @Test
    public void test03() {

        assertThat(lists.stream().count()).isEqualTo(10);
        // map 函数传进去一个泛型 返回一个泛型
        lists.stream().map(s -> s.setName(s.getName().toUpperCase())).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println();
        lists.stream()
//                .limit(5)//添加了limit后 只输出5个
//                .filter(d -> d.getName().equals("DOG0")) // 只输出判断条件等于true的
                .collect(Collectors.toList()).forEach(System.out::println);

        assertThat(lists.stream().allMatch(s -> s.getName().contains("DOG"))).isTrue();//判断所有的name都包含DOG
        assertThat(lists.stream().anyMatch(s -> s.getName().contains("DOG1"))).isTrue();//判断所有的name都包含DOG

        nums.stream().distinct().forEach(System.out::println);//可以自动去重
        System.out.println();
        // 把2个list里面的内容和并然后输出list
        Stream.of(lists, repeats).flatMap(u -> u.stream()).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println();
        // 把2个list里面的内容和并然后输出map
        Stream.of(lists, repeats).flatMap(Collection::stream).collect(Collectors.toMap(Dog::getName, Function.identity(), (t, t1) -> t)).forEach((k, v) -> System.out.println(k + " " + v));
        System.out.println();
        //把对象转为stream
        Stream.of(new Dog("name", "like")).collect(Collectors.toList()).forEach(System.out::println);

        List<Dog> collect = Stream.of(lists, repeats).flatMap(Collection::stream).collect(Collectors.toList());


        System.out.println(1);
        System.out.println(2);
        System.out.println(3);



    }


    @Test
    public void test02() {

        Map<String, Dog> collect = lists.stream().collect(Collectors.toMap(Dog::getName, Function.identity()));
        System.out.println(collect);

        System.out.println(repeats.stream().collect(Collectors.toMap(Dog::getName,
                Function.identity(),
                (t, t1) -> t))); // 主键相同，合并函数

        System.out.println(repeats.stream().collect(Collectors.toMap(Dog::getName,
                Function.identity(),
                (t, t1) -> t,
                (Supplier<HashMap>) LinkedHashMap::new)));//可以选择返回的map的类型

        assertThat(repeats.stream().collect(Collectors.toMap(Dog::getName,
                Function.identity(),
                (t, t1) -> t,
                (Supplier<HashMap>) LinkedHashMap::new)).getClass()).isAssignableFrom(LinkedHashMap.class);
    }


    @Test
    public void test01() {
        assertThat(lists.size()).isEqualTo(10);
    }



}
